package org.lhl.readruler.utils

import com.google.gson.*
import com.google.gson.annotations.Expose
import com.google.gson.reflect.TypeToken
import lhl.kotlinextends.e
import java.lang.reflect.Type

/**
 * Created by luohaolun.
 * Date: 2019/5/21
 */
val gson by lazy {
    GsonBuilder().apply {
        addSerializationExclusionStrategy(object : ExclusionStrategy {
            override fun shouldSkipField(f: FieldAttributes?): Boolean {
                return f?.getAnnotation(Expose::class.java)?.let { !it.serialize } ?: false
            }

            override fun shouldSkipClass(clazz: Class<*>?) = false
        })
        addDeserializationExclusionStrategy(object : ExclusionStrategy {
            override fun shouldSkipField(f: FieldAttributes?): Boolean {
                return f?.getAnnotation(Expose::class.java)?.let { !it.deserialize } ?: false
            }

            override fun shouldSkipClass(clazz: Class<*>?): Boolean = false
        })
        ScalarsJsonDeserializer.types.forEach { registerTypeAdapter(it, ScalarsJsonDeserializer) }
    }.create()
}

fun Any.toJson(): String {
    return gson.toJson(this)
}

inline fun <reified T> String.deserialize(): T? {
    return try {
        gson.fromJson<T>(this, object : TypeToken<T>() {}.type)
    } catch (e: Exception) {
        "反序列化${T::class.java} 失败".e()
        e.e()
        null
    }
}

inline fun <reified T> Gson.fromJson(value: String): T {
    return fromJson(value, T::class.java)
}

private object ScalarsJsonDeserializer : JsonDeserializer<Any> {
    val types = arrayOf<Type>(
        String::class.java,
        Boolean::class.java,
        Byte::class.java,
        Char::class.java,
        Double::class.java,
        Float::class.java,
        Int::class.java,
        Long::class.java,
        Short::class.java
    )

    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Any? {
        return try {
            when (typeOfT) {
                String::class.java -> json?.asString
                Boolean::class.java -> json?.asBoolean
                Byte::class.java -> json?.asByte
                Char::class.java -> json?.asCharacter
                Double::class.java -> json?.asDouble
                Float::class.java -> json?.asFloat
                Int::class.java -> json?.asInt
                Long::class.java -> json?.asLong
                Short::class.java -> json?.asShort
                else -> {
                    if (typeOfT.toString().contains("java.lang.String"))
                        json?.asString
                    else {
                        "未知类型 $typeOfT".e()
                        null
                    }
                }
            }
        } catch (e: Exception) {
//            "反序列化异常$typeOfT  $e".e()
            when (typeOfT) {
                String::class.java -> ""
                Boolean::class.java -> false
                else -> 0
            }
        }
    }
}